import { useEffect, useMemo, useRef, useState } from 'react';
import { isArray, isEqual, isFunction } from 'lodash-es';

import TreeStore from '@tdesign/common-js/tree-v1/tree-store';
import type { TypeTreeNodeData } from '@tdesign/common-js/tree-v1/types';

import useControlled from '../hooks/useControlled';
import useDefaultProps from '../hooks/useDefaultProps';
import { treeNodesEffect, treeStoreExpendEffect } from './core/effect';
import { getCascaderValue, getTreeValue, isEmptyValues, isValueInvalid } from './core/helper';
import { cascaderDefaultProps } from './defaultProps';

import type { TreeOptionData } from '../common';
import type {
  CascaderChangeSource,
  CascaderValue,
  TdCascaderProps,
  TreeNode,
  TreeNodeModel,
  TreeNodeValue,
} from './interface';

export const useCascaderContext = (originalProps: TdCascaderProps) => {
  const props = useDefaultProps(originalProps, cascaderDefaultProps);
  const { disabled, options, keys = {}, checkStrictly, lazy, multiple, reserveKeyword, valueMode, load } = props;

  const [innerValue, setInnerValue] = useControlled(props, 'value', props.onChange);
  const [innerPopupVisible, setPopupVisible] = useControlled(props, 'popupVisible', props.onPopupVisibleChange);

  const [inputVal, setInputVal] = useState('');
  const [treeStore, setTreeStore] = useState(null);
  const [treeNodes, setTreeNodes] = useState<TreeNode[]>([]);
  const [expend, setExpend] = useState<TreeNodeValue[]>([]);
  const [scopeVal, setScopeVal] = useState(undefined);

  // valueMode = 'parentFirst' || 'all' 和 checkStrictly 都允许父节点被选中
  const isParentFilterable = useMemo(
    () => !!((['parentFirst', 'all'].includes(props.valueMode) || props.checkStrictly) && inputVal),
    [props.valueMode, props.checkStrictly, inputVal],
  );

  const cascaderContext = useMemo(() => {
    const {
      size,
      checkStrictly,
      lazy,
      multiple,
      filterable,
      clearable,
      checkProps,
      max,
      disabled,
      showAllLevels,
      minCollapsedNum,
      valueType,
    } = props;
    return {
      value: scopeVal,
      size,
      checkStrictly,
      lazy,
      multiple,
      filterable,
      clearable,
      checkProps,
      max,
      disabled,
      showAllLevels,
      minCollapsedNum,
      valueType,
      treeStore,
      setValue: (val: CascaderValue, source: CascaderChangeSource, node?: TreeNodeModel) => {
        if (isEqual(val, scopeVal)) return;
        setInnerValue(val, { source, node });
      },
      visible: innerPopupVisible,
      setVisible: setPopupVisible,
      treeNodes,
      setTreeNodes,
      inputVal,
      setInputVal,
      setExpend,
      isParentFilterable,
    };
  }, [
    props,
    scopeVal,
    innerPopupVisible,
    treeStore,
    treeNodes,
    inputVal,
    setInnerValue,
    setPopupVisible,
    isParentFilterable,
  ]);

  const isFilterable = useMemo(
    () => Boolean(props.filterable || isFunction(props.filter)),
    [props.filterable, props.filter],
  );

  /**
   * build tree
   */

  const optionCurrent = useRef([]);

  useEffect(() => {
    if (!isEqual(optionCurrent.current, options)) {
      optionCurrent.current = options;
      // eslint-disable-next-line @typescript-eslint/no-use-before-define
      handleTreeStore();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [options]);

  const handleTreeStore = () => {
    if (!treeStore) {
      if (!options.length) return;
      const store = new TreeStore({
        keys: {
          ...keys,
          children: typeof keys.children === 'string' ? keys.children : 'children',
        },
        onLoad: () => {
          setTimeout(() => {
            store.refreshNodes();
            treeNodesEffect(inputVal, store, setTreeNodes, props.filter, isParentFilterable);
          });
        },
      });
      store.append(options as Array<TypeTreeNodeData>);

      setTreeStore(store);
    } else {
      treeStore.reload(options);
      treeStore.refreshNodes();
      treeStoreExpendEffect(treeStore, scopeVal, []);
      treeNodesEffect(inputVal, treeStore, setTreeNodes, props.filter, isParentFilterable);
    }
  };

  useEffect(() => {
    if (!treeStore) return;
    const treeProps = {
      keys: {
        ...keys,
        children: typeof keys.children === 'string' ? keys.children : 'children',
      },
      checkable: true,
      expandMutex: true,
      expandParent: true,
      checkStrictly,
      disabled,
      load,
      lazy,
      valueMode,
    };
    treeStore.setConfig(treeProps);
  }, [checkStrictly, disabled, keys, lazy, load, valueMode, treeStore]);

  // value 校验逻辑
  useEffect(() => {
    const { setValue, multiple, valueType = 'single' } = cascaderContext;

    if (isValueInvalid(innerValue, cascaderContext)) {
      setValue(multiple ? [] : '', 'invalid-value');
    }

    if (!isEmptyValues(innerValue)) {
      setScopeVal(getCascaderValue(innerValue, valueType, multiple));
    } else {
      setScopeVal(multiple ? [] : '');
    }

    if (multiple && !reserveKeyword) {
      setInputVal('');
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [innerValue, multiple, reserveKeyword]);

  useEffect(() => {
    if (!treeStore) return;
    treeStoreExpendEffect(treeStore, scopeVal, expend);
  }, [treeStore, scopeVal, expend]);

  useEffect(() => {
    if (!treeStore) return;
    treeNodesEffect(inputVal, treeStore, setTreeNodes, props.filter, isParentFilterable);
  }, [inputVal, treeStore, props.filter, isParentFilterable]);

  useEffect(() => {
    if (!treeStore) return;
    treeStore.replaceChecked(getTreeValue(scopeVal));
  }, [options, scopeVal, treeStore, multiple]);

  useEffect(() => {
    if (!innerPopupVisible && isFilterable) {
      setInputVal('');
    }
  }, [innerPopupVisible, isFilterable]);

  useEffect(() => {
    const { inputVal, treeStore, setTreeNodes } = cascaderContext;
    treeNodesEffect(inputVal, treeStore, setTreeNodes, props.filter, isParentFilterable);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [inputVal, scopeVal, isParentFilterable]);

  const getCascaderItems = (
    arrValue: CascaderValue[],
    valueType: TdCascaderProps['valueType'],
    multiple: TdCascaderProps['multiple'],
  ) => {
    const { treeStore } = cascaderContext;
    const optionsData: TreeOptionData[] = [];

    if (!treeStore) return optionsData;

    if (valueType === 'full') {
      if (multiple) {
        // 未来需支持全路径拼接搜索
        arrValue.forEach((value) => {
          if (isArray(value) && value.length) {
            const nodeValue = value[value.length - 1];
            const [node] = treeStore.getNodes(nodeValue) || [];
            node?.data && optionsData.push(node.data);
          }
        });
      } else if (isArray(arrValue) && arrValue.length) {
        const nodeValue = arrValue[arrValue.length - 1];
        const [node] = treeStore.getNodes(nodeValue) || [];
        node?.data && optionsData.push(node.data);
      }
    } else if (valueType === 'single') {
      arrValue.forEach((value) => {
        const [node] = treeStore.getNodes(value) || [];
        node?.data && optionsData.push(node.data);
      });
    }

    return optionsData;
  };

  return {
    cascaderContext,
    isFilterable,
    innerValue,
    getCascaderItems,
  };
};
